﻿using System;

namespace ITSP_Instance_Generator
{
    class SA // simulated annealing
    {
        public Instance Instance;
        private double _temperature;
        private const double TemperatureAlpha = 0.9; // between 0 and 1, newTemp = oldTemp * tempAlpha
        private static readonly Random Random = new Random();
        public double bestFoundTourCostTestVar = 0;
        public int nrIts = 0;
        public SA(Instance instance)
        {
            Instance = instance;
            _temperature = 100;
        }

        private void CoolDown() // todo read paper about cooling strategies
        {
            _temperature *= TemperatureAlpha;
        }
        private bool Accept(SA_Instance originalInstance, SA_Instance newInstance)
        {
            double deltaCost = newInstance.TourCost - originalInstance.TourCost;
            if (deltaCost < 0)
                return true;
            if (Math.Exp(-deltaCost/_temperature) > Random.NextDouble())
                return true;
            return false;

        }
        public void Run()
        {
            int nrIterationsNoAccept = 0; // Iterations of outer loop without any instances being accepted in the inner loop
            SA_Instance saInstance = new SA_Instance(Instance);
            bestFoundTourCostTestVar = saInstance.TourCost;
            while (nrIterationsNoAccept < 3)
            {
                bool acceptedAtleastOne = false;
                int nrInnerIterations = 0;
                while ((nrInnerIterations++)<5)
                {
                    if(nrIts%100000 == 0)
                        Console.WriteLine(nrIts + "\t" + bestFoundTourCostTestVar + "\t" + saInstance.arrayToString(saInstance.NodeOrder));

                    nrIts++;



                    SA_Instance nextSAInstance = saInstance.GenerateNextMove();
                    if (Accept(saInstance, nextSAInstance))
                    {
                        saInstance = nextSAInstance;
                        acceptedAtleastOne = true;
                        if (saInstance.TourCost > bestFoundTourCostTestVar)
                        {
                            bestFoundTourCostTestVar = saInstance.TourCost;
                            Console.Write(bestFoundTourCostTestVar);
                        }
                        bestFoundTourCostTestVar = saInstance.TourCost;
                    }
                    else
                    {

                    }
                }
                if (!acceptedAtleastOne)
                    nrIterationsNoAccept++;
                else
                    nrIterationsNoAccept = 0;
                CoolDown();
            }
        }
    }
}
